#include "build_cmd.h"

static int scsi_report_lun_cmd_done(scsi_cmd_t *cmd)
{
    unsigned int lun_num = 0;    
    lun_num |= cmd->data_out_buffer[0] << 24;
    lun_num |= cmd->data_out_buffer[1] << 16;
    lun_num |= cmd->data_out_buffer[2] << 8;
    lun_num |= cmd->data_out_buffer[3];
    printk("lun_num=%u\n", lun_num);
    return 0;
}

void build_scsi_report_lun_cmd(scsi_cmd_t *cmd)
{
    cmd->data_out_buffer_len = DEFAULT_SCSI_OUT_BUFF_LEN;
    cmd->callback = scsi_report_lun_cmd_done;
    cmd->scsi_cmd[0] = REPORT_LUNS;
    cmd->scsi_cmd[2] = 0x02;
    cmd->scsi_cmd[6] = 0;
    cmd->scsi_cmd[7] = 0;
    cmd->scsi_cmd[8] = 0x02;
    cmd->scsi_cmd[9] = 0;
}

static int scsi_tur_cmd_done(scsi_cmd_t *cmd)
{
    if (cmd->exec_args.sshdr == NULL) {
        return -1;
    }
    printk("response_code=%u\n", cmd->exec_args.sshdr->response_code);
    printk("sense_key=%u\n", cmd->exec_args.sshdr->sense_key);
    printk("asc=%u\n", cmd->exec_args.sshdr->asc);
    printk("ascq=%u\n", cmd->exec_args.sshdr->ascq);
    return 0;
}

void build_scsi_tur_cmd(scsi_cmd_t *cmd)
{
    cmd->callback = scsi_tur_cmd_done;
    cmd->scsi_cmd[0] = TEST_UNIT_READY;
}

static int scsi_inquiry_cmd_done(scsi_cmd_t *cmd)
{
    unsigned char peripheral_qualifier = 0;
    unsigned char peripheral_type = 0;
    int scsi_version = 0;
    int response_len = 0;
    char product[17] = {0};

    peripheral_qualifier = cmd->data_out_buffer[0] & 0xe0;
    peripheral_type = cmd->data_out_buffer[0] & 0x1f;
    scsi_version = (int)cmd->data_out_buffer[2];
    response_len = (int)cmd->data_out_buffer[4] + 5;
    memcpy(product, &cmd->data_out_buffer[16], 16);
    product[16] = '\0';

    printk("peripheral_qualifier=%u\n", peripheral_qualifier);
    printk("peripheral_type=%u\n", peripheral_type);
    printk("scsi_version=%d\n", scsi_version);
    printk("response_len=%d\n", response_len);
    printk("product=%s\n", product);
    return 0;
}

void build_scsi_inquiry_cmd(scsi_cmd_t *cmd)
{
    cmd->data_out_buffer_len = 36;
    cmd->callback = scsi_inquiry_cmd_done;
    cmd->scsi_cmd[0] = INQUIRY;
    cmd->scsi_cmd[4] = (unsigned char)cmd->data_out_buffer_len;
}

static int scsi_inquiry_0x00_cmd_done(scsi_cmd_t *cmd)
{
    int page_len = 0;
    page_len = (int)cmd->data_out_buffer[3];
    printk("page_len=%d\n", page_len);
    for (int i = 0; i < page_len; i++) {
        printk("page_code=0x%x\n", (unsigned int)cmd->data_out_buffer[4 + i]);
    }
    return 0;
}

void build_scsi_inquiry_0x00_cmd(scsi_cmd_t *cmd)
{
    cmd->data_out_buffer_len = 36;
    cmd->callback = scsi_inquiry_0x00_cmd_done;
    cmd->scsi_cmd[0] = INQUIRY;
    cmd->scsi_cmd[1] = 0x01;
    cmd->scsi_cmd[2] = 0x00;
    cmd->scsi_cmd[4] = (unsigned char)cmd->data_out_buffer_len;
}

static int scsi_inquiry_0x80_cmd_done(scsi_cmd_t *cmd)
{
    int page_len = 0;
    page_len = (int)cmd->data_out_buffer[3];
    printk("page_len=%d\n", page_len);
    return 0;
}

void build_scsi_inquiry_0x80_cmd(scsi_cmd_t *cmd)
{
    cmd->data_out_buffer_len = 36;
    cmd->callback = scsi_inquiry_0x80_cmd_done;
    cmd->scsi_cmd[0] = INQUIRY;
    cmd->scsi_cmd[1] = 0x80;
    cmd->scsi_cmd[2] = 0x80;
    cmd->scsi_cmd[4] = (unsigned char)cmd->data_out_buffer_len;
}

static int scsi_inquiry_0x83_cmd_done(scsi_cmd_t *cmd)
{
    int page_len = 0;
    page_len = (int)cmd->data_out_buffer[3];
    printk("page_len=%d\n", page_len);
    return 0;
}

void build_scsi_inquiry_0x83_cmd(scsi_cmd_t *cmd)
{
    cmd->data_out_buffer_len = 36;
    cmd->callback = scsi_inquiry_0x83_cmd_done;
    cmd->scsi_cmd[0] = INQUIRY;
    cmd->scsi_cmd[1] = 0x01;
    cmd->scsi_cmd[2] = 0x83;
    cmd->scsi_cmd[4] = (unsigned char)cmd->data_out_buffer_len;
}

static int scsi_read_capacity_cmd_done(scsi_cmd_t *cmd)
{
    unsigned int lba_size = 0;
    unsigned int blk_size = 0;
    unsigned int cap = 0;

    lba_size |= cmd->data_out_buffer[0] << 24;
    lba_size |= cmd->data_out_buffer[1] << 16;
    lba_size |= cmd->data_out_buffer[2] << 8;
    lba_size |= cmd->data_out_buffer[3];

    blk_size |= cmd->data_out_buffer[4] << 24;
    blk_size |= cmd->data_out_buffer[5] << 16;
    blk_size |= cmd->data_out_buffer[6] << 8;
    blk_size |= cmd->data_out_buffer[7];

    cap = (lba_size * blk_size)/1024/1024;
    printk("lba_size=%u\n", lba_size);
    printk("blk_size=%u\n", blk_size);
    printk("cap=%u\n", cap);
    return 0;
}

void build_scsi_read_capacity_cmd(scsi_cmd_t *cmd)
{
    cmd->data_out_buffer_len = 8;
    cmd->callback = scsi_read_capacity_cmd_done;
    cmd->scsi_cmd[0] = READ_CAPACITY;
}

static int scsi_read10_cmd_done(scsi_cmd_t *cmd)
{
    printk("read_data=%s\n", cmd->data_out_buffer);
    return 0;
}

void build_scsi_read10_cmd(scsi_cmd_t *cmd)
{
    cmd->data_out_buffer_len = DEFAULT_SCSI_OUT_BUFF_LEN;
    cmd->callback = scsi_read10_cmd_done;
    cmd->scsi_cmd[0] = READ_10;
    // cmd->scsi_cmd[1] |= 0x20; /* PROTECT */
    cmd->scsi_cmd[1] |= 0x08; /* FUA */
    // cmd->scsi_cmd[1] |= 0x10; /* DPO */
    cmd->scsi_cmd[8] = 0x1;
}

void build_cmd_init()
{
    register_build_scsi_cmd_func(build_scsi_inquiry_cmd);
}
